package com.flycent.fanbao.net;

import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

import org.apache.http.Header;

import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.os.Handler;
import android.os.UserManager;

import com.flycent.fanbao.App;
import com.flycent.fanbao.ui.BaseActivity;
import com.flycent.fanbao.util.PackageInfoUtil;
import com.flycent.fanbao.util.StringUtil;
import com.google.gson.Gson;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import com.loopj.android.http.SyncHttpClient;
import com.loopj.android.http.TextHttpResponseHandler;

/**
 * 网络请求类，所有网络请求都要通过该类来进行
 * <p> 该类包含基本的网络请求方法 
 * <ul>
 * 	<li>{@link HttpMethod #GET}
 * 	<li>{@link HttpMethod #POST}
 * 	<li>{@link HttpMethod #PUT}
 * 	<li>{@link HttpMethod #DELETE}
 * </ul>
 * 
 * NOTE : 若在  {@link Activity} 或 {@link Service} 中使用网络请求，应该在其销毁 onDestory()  的时候
 * 调用 {@link HttpRequestClient #cancleRequest}方法, 防止内存泄漏等异常
 * 
 * @author Liu.Wenzhu <lwz0316@gmail.com>
 * @date 2014年7月5日 上午11:31:42
 */
public class HttpRequestClient {
	
	public static final String LOG_TAG = "HttpRequestClient";
	
	private static final int DEFAULT_TETRY_TIMES = 1;			// 重试次数
	private static final int DEFAULT_TIMEOUT = 15 * 1000;		// 连接超时时间
	private static final int DEFAULT_MAX_CONNECTIONS = 10;		// 最大连接数
	
	private static AsyncHttpClient msAsyncHttpClient;
	private static Handler mLoadingDialogHandler = new Handler();

	/**
	 * GET 请求
	 * @param url				请求的 URL
	 * @param params			参数，可为 null
	 * @param responseHandler	响应处理器
	 */
	public static void get(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
		params = signParams(params);
		App.debug(LOG_TAG, "GET : " + url + " @ " + (params == null ? "null" : params.toString()));
		responseHandler.setRequestURI(URI.create(url));
		if( loadCacheData(responseHandler) ) {
			AsyncHttpClient client = getDefaultClient();
			client.get(context, url, params, new AsyncResponseHandlerWrapper(context, responseHandler));
		}
	}
	
	/**
	 * POST 请求
	 * @param url				请求的 URL
	 * @param params			参数，可为 null
	 * @param responseHandler	响应处理器
	 */
	public static void post(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
		params = signParams(params);
		App.debug(LOG_TAG, "POST : " + url + " @ " + (params == null ? "" : params.toString()));
		responseHandler.setRequestURI(URI.create(url));
		if( loadCacheData(responseHandler) ) {
			AsyncHttpClient client = getDefaultClient();
			client.post(context, url, params, new AsyncResponseHandlerWrapper(context,responseHandler));
		}
	}
	
	/**
	 * PUT 请求
	 * @param url				请求的 URL
	 * @param params			参数，可为 null
	 * @param responseHandler	响应处理器
	 */
	public static void put(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
		params = signParams(params);
		App.debug(LOG_TAG, "PUT : " + url + " @ " + (params == null ? "null" : params.toString()));
		AsyncHttpClient client = getDefaultClient();
		params.setUseJsonStreamer(true);
		client.put(context, url, params, new AsyncResponseHandlerWrapper(context, responseHandler));
	}
	
	/**
	 * DELETE 请求
	 * @param url				请求的 URL
	 * @param params			参数，可为 null
	 * @param responseHandler	响应处理器
	 */
	public static void delete(Context context, String url, AsyncHttpResponseHandler responseHandler) {
		App.debug(LOG_TAG, "DELETE : " + url);
		AsyncHttpClient client = getDefaultClient();
		client.delete(context, url, new AsyncResponseHandlerWrapper(context, responseHandler));
	}
	
	public synchronized static AsyncHttpClient getDefaultClient() {
		if( msAsyncHttpClient == null ) {
			AsyncHttpClient client = new AsyncHttpClient(80, 443);
			Locale locale = Locale.getDefault();
			client.addHeader("Accept-Language", (locale.getLanguage()+"-"+locale.getCountry()).toLowerCase(locale));
			client.addHeader("Accept-Encoding", "gzip");
			client.setTimeout(DEFAULT_TIMEOUT);
			client.setMaxRetriesAndTimeout(DEFAULT_TETRY_TIMES, DEFAULT_TIMEOUT);
			client.setMaxConnections(DEFAULT_MAX_CONNECTIONS);
			client.setUserAgent("formica,android," + PackageInfoUtil.getVersionName(App.getInstance()));
			msAsyncHttpClient = client;
		}
		return msAsyncHttpClient;
	}
	
	public static SyncHttpClient createSyncClient() {
		SyncHttpClient client = new SyncHttpClient(80, 443);
		Locale locale = Locale.getDefault();
		client.addHeader("Accept-Language", (locale.getLanguage()+"-"+locale.getCountry()).toLowerCase(locale));
		client.addHeader("Accept-Encoding", "gzip");
		client.setTimeout(DEFAULT_TIMEOUT);
		client.setMaxRetriesAndTimeout(DEFAULT_TETRY_TIMES, DEFAULT_TIMEOUT);
		client.setMaxConnections(DEFAULT_MAX_CONNECTIONS);
		client.setUserAgent("formica,android," + PackageInfoUtil.getVersionName(App.getInstance()));
		return client;
	}
	
	/**
	 * 取消请求
	 * <p>若在  {@link Activity} 或 {@link Service} 中使用网络请求，应该在其销毁 onDestory()  的时候调用该方法,
	 * 防止内存泄漏等异常
	 * @param context
	 */
	public static void cancleRequest(final Context context) {
		Thread cancleThread = new Thread() {
			
			@Override
			public void run() {
				getDefaultClient().cancelRequests(context, true);
				getDefaultClient().cancelRequests(context, true);
				App.debug(LOG_TAG, "cancleRequest : " + context.getClass().getSimpleName());
			}
		};
		cancleThread.setPriority(Thread.MAX_PRIORITY);
		cancleThread.run();
	}
	
	private static final String YYYYMMddHHmmss = "yyyyMMddHHmmss";
	
	private static RequestParams signParams(RequestParams params) {
		if( params == null ) return null;
//		UserManager manager = UserManager.getInstance();
//		if( manager.isLogin() ) {
//			final String timestamp = StringUtil.formatDate(YYYYMMddHHmmss, System.currentTimeMillis());
//			params.put("zsign", MD5Util.encode(manager.getToken() + timestamp + App.SECRET));
//			params.put("ztimestamp", timestamp);
//		}
		return params;
	}
	
	
	/**
	 * 加载缓存后是否还需要请求数据
	 * @param responseHandler
	 * @return true 还需要请求数据，false 不需要请求数据
	 */
	public static boolean loadCacheData(AsyncHttpResponseHandler responseHandler) {
//		if( responseHandler instanceof CacheLoadResponseHandler ) {
//			CacheLoadResponseHandler handler = (CacheLoadResponseHandler) responseHandler;
//			try {
//				final String cachedString =
//						RequestDataCacheManager.restoreData(handler.getCacheKey());
//				Object data = new Gson().fromJson(cachedString, handler.getCachedDataType());
//				final String url = (responseHandler.getRequestURI() == null ? "" : responseHandler.getRequestURI().toString());
//				if( data != null ) {
//					registerUnshowDialogAPIFilter.add(url);
//					handler.onLoadCache(data);
//					return handler.isNeedRequestDataIfHasCache();
//				} else {
//					registerUnshowDialogAPIFilter.remove(url);
//				}
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//		}
		return true;
	}
	
	public static Set<String> registerUnshowDialogAPIFilter = new HashSet<String>();
	
	static class AsyncResponseHandlerWrapper extends AsyncHttpResponseHandler {
		private WeakReference<Context> referenceContext;
		private AsyncHttpResponseHandler handlerInterface;
		
		public AsyncResponseHandlerWrapper(Context context, AsyncHttpResponseHandler handler) {
			this.referenceContext = new WeakReference<Context>(context);
			this.handlerInterface = handler != null ? handler : new TextHttpResponseHandler() {
				public void onSuccess(int statusCode, Header[] headers, String responseString) {}
				public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {}
			};
		}

		@Override
		public URI getRequestURI() {
			return handlerInterface.getRequestURI();
		}

		@Override
		public Header[] getRequestHeaders() {
			return handlerInterface.getRequestHeaders();
		}

		@Override
		public void setRequestURI(URI requestURI) {
			handlerInterface.setRequestURI(requestURI);
		}

		@Override
		public void setRequestHeaders(Header[] requestHeaders) {
			handlerInterface.setRequestHeaders(requestHeaders);
		}

		@Override
		public void setUseSynchronousMode(boolean useSynchronousMode) {
			handlerInterface.setUseSynchronousMode(useSynchronousMode);
		}

		@Override
		public boolean getUseSynchronousMode() {
			return handlerInterface.getUseSynchronousMode();
		}
		
		@Override
		public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
			handlerInterface.onSuccess(statusCode, headers, responseBody);
		}

		@Override
		public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
			if( registerUnshowDialogAPIFilter.contains(getRequestURI().toString().split("\\?", 1)[0]) ) {
				return;
			}
			handlerInterface.onFailure(statusCode, headers, responseBody, error);
		}

		@Override
		public void onProgress(int bytesWritten, int totalSize) {
			super.onProgress(bytesWritten, totalSize);
			handlerInterface.onProgress(bytesWritten, totalSize);
		}

		@Override
		public void onStart() {
			super.onStart();
			publishShowLoadingDialogEvent();
			handlerInterface.onStart();
		}

		@Override
		public void onFinish() {
			super.onFinish();
			handlerInterface.onFinish();
			publishDismissLoadingDialogEvent();
			App.debug(getRequestURI() + "   onFinish");
		}

		@Override
		public void onRetry(int retryNo) {
			super.onRetry(retryNo);
			handlerInterface.onRetry(retryNo);
		}

		@Override
		public void onCancel() {
			super.onCancel();
			handlerInterface.onCancel();
		}
		
		private void publishShowLoadingDialogEvent() {
			if( registerUnshowDialogAPIFilter.contains(getRequestURI().toString().split("\\?", 1)[0]) ) {
				return;
			}
			final Context context = referenceContext.get();
			if( context == null || !( context instanceof BaseActivity)) {
				return;
			}
//			if( handlerInterface instanceof CacheLoadResponseHandler<?, ?> ) {
//				// 有缓存就不显示 loading dialog 了;
//				if( ((CacheLoadResponseHandler<?, ?>) handlerInterface).hasCachedData() ) {
//					return;
//				}
//			}
//			mLoadingDialogHandler.removeCallbacksAndMessages(null);
//			mLoadingDialogHandler.postDelayed(new Runnable() {
//				@Override public void run() {
//					ShowOrDismissLoadingDialogEvent event = new ShowOrDismissLoadingDialogEvent();
//					event.context = context;
//					event.isShow = true;
//					EventBus.getDefault().post(event);
//				}
//			}, 500);
		}
		
		private void publishDismissLoadingDialogEvent() {
//			if( registerUnshowDialogAPIFilter.contains(getRequestURI().toString()) ) {
//				return;
//			}
//			mLoadingDialogHandler.removeCallbacksAndMessages(null);
//			Context context = referenceContext.get();
//			if( context == null  || !( context instanceof BaseActivity)  ) {
//				return;
//			}
//			ShowOrDismissLoadingDialogEvent event = new ShowOrDismissLoadingDialogEvent();
//			event.context = context;
//			event.isShow = false;
//			EventBus.getDefault().post(event);
		}
		
	}
	
}
